# -*- coding: utf-8 -*-
# This code written by ChanGOGOGO
"""
新建的外呼任务导入号码后，及时通知数据经理开启任务外呼
"""
import json
import logging
import os
import time
from logging.handlers import RotatingFileHandler
import pymysql
import requests
import yaml
from elasticsearch import Elasticsearch
from apscheduler.schedulers.blocking import BlockingScheduler


def get_today_date():
    today = time.strftime("%Y-%m-%d", time.localtime())
    return today


def get_start_end_time():
    """获取今天的开始结束时间"""
    today = get_today_date()
    start_time = f"{today} 00:00:00"
    end_time = f"{today} 23:59:59"
    return start_time, end_time


def setup_logging(log_level: str = "INFO", write_log: bool = True):
    """
    日志格式化打印
    :param log_level: 打印高于等于设定级别的日志。DEBUG < INFO < WARNING < ERROR < CRITICAL
    :param write_log: 是否需要将日志写入到文件
    :return: None
    """
    # 创建日志器
    logger = logging.getLogger()
    logger.setLevel(log_level)  # 设置日志级别为DEBUG
    # 设置日志格式
    formatter = logging.Formatter(
        "%(asctime)s [%(levelname)s]：%(message)s", datefmt="%Y-%m-%d %H:%M:%S"
    )
    # 创建一个流处理器，输出到控制台
    console_handler = logging.StreamHandler()
    console_handler.setFormatter(formatter)
    logger.addHandler(console_handler)
    # 根据参数决定是否也将日志写入文件
    if write_log:
        # 确保日志目录存在
        if not os.path.exists("logs"):
            os.makedirs("logs")
        # 创建一个循环文件处理器，自动根据大小切割
        file_handler = RotatingFileHandler(
            "logs/info.log", maxBytes=1048576, backupCount=5, encoding="utf-8"
        )
        file_handler.setFormatter(formatter)
        logger.addHandler(file_handler)


setup_logging()


def read_yaml(config_path=r"./config/client_config.yaml"):
    """读取yaml文件"""
    with open(config_path, encoding="utf-8") as f:
        config = yaml.safe_load(f)
    return config


def data2beautify(data):
    """
    将字典或列表类型的数据进行美化输出。

    :param data: 需要格式化的字典或列表类型数据
    :return: 格式化后的字符串
    """
    if data is None:
        return "输入为空"

    if not isinstance(data, (dict, list)):
        return "输入必须是字典或列表类型"

    try:
        formatted_data = json.dumps(data, indent=4, ensure_ascii=False)
        return formatted_data
    except (TypeError, ValueError) as e:
        return f"格式化失败: {str(e)}"


def wecom_push_msg(qw_push_url, msg):
    """向企微群推送消息"""
    data = {"msgtype": "markdown", "markdown": {"content": msg}}
    logging.info(f"向企微群推送消息接口发起请求：\n{data2beautify(data)}")
    res = requests.post(qw_push_url, data=json.dumps(data)).json()
    logging.info(f"收到企微群推送消息接口响应：\n{data2beautify(res)}")
    return res


task_status_info = {
    0: "未开始",  # 创建任务，尚未导入号码
    1: "未开始",  # 导入号码完成
    5: "队列中",
    10: "进行中",  # 包含：进行中、空闲、非营业时段
    20: "手动暂停",
    21: "异常暂停",
    25: "已完成",  # 从界面点了任务结束, 作为中间状态，事实上是任务终止中
    30: "已完成",
    40: "已过期",
    50: "被删除",  # 任务被删除掉了
}


class StartTaskNotice:
    def __init__(self, env: str):
        if env.lower() not in ["dev", "uat", "pls"]:
            logging.error(f"传入环境为{env}，限制环境只能为dev/uat/pls")
        config_path = f"./config/{env}.yaml"
        self.config = read_yaml(config_path)
        self.push_url = self.config.get("push_url")
        self.fandeng_push_url = self.config.get("fandeng_push_url")
        self.fandeng_company_id = self.config.get("fandeng_company_id")
        db_ip = self.config.get("db_info").get("ip")
        db_port = self.config.get("db_info").get("port")
        user = self.config.get("db_info").get("user")
        passwd = self.config.get("db_info").get("password")
        self.conn = pymysql.connect(
            host=db_ip, port=db_port, user=user, passwd=passwd, charset="utf8"
        )
        self.cursor = self.conn.cursor()
        self.exclude_company_ids = self.config.get(
            "exclude_company_ids"
        )  # 不需要通知的账号id（company_id）
        es_ip = self.config.get("elastic_search_info").get("ip")
        es_port = self.config.get("elastic_search_info").get("port")
        self.es = Elasticsearch(
            hosts=[f"http://{es_ip}:{es_port}"],
            headers={"Content-Type": "application/json"},
        )

    def query_es(self, es_index, body):
        """查询ES"""
        logging.info(f"向Elasticsearch的{es_index}发起请求：\n{data2beautify(body)}")
        result = self.es.count(index=es_index, body=body)
        logging.info(f"从Elasticsearch的{es_index}得到响应：\n{data2beautify(result)}")
        count = result.get("count")
        return count

    def query_business(self) -> list:
        """查询各账号下的业务"""
        sql = f"""select * from (select a.company_id,b.bid from yicall_business.yicall_aiforce_user a RIGHT JOIN 
        yicall_business.yicall_aiforce_instance b on a.company_id=b.company_id where a.company_id>=1000 
        ORDER BY a.company_id) temp GROUP BY company_id,bid;"""
        logging.info(f"查询所有的业务信息SQL：\n{sql}")
        self.cursor.execute(sql)
        company_business_id = self.cursor.fetchall()
        logging.info(f"查询到各账号下业务信息：\n{data2beautify(company_business_id)}")
        company_business_info = list()
        for x in company_business_id:
            company_id, business_id = x
            sql = f"""select pid,business_id,business_name from yicall_{company_id}.call_business 
            where pid={company_id} and business_id={business_id};"""
            self.cursor.execute(sql)
            result = self.cursor.fetchall()
            company_business_info.append(result[0])
        logging.info(
            f"查询到全部账号下的业务信息：\n{data2beautify(company_business_info)}"
        )
        return company_business_info

    def query_task_info(self, company_id, business_id):
        """查询账号下某个业务需要开启拨打的任务信息"""
        start_time, end_time = get_start_end_time()
        if company_id not in self.exclude_company_ids:
            sql = f"""select task_id,task_name,task_status,dialog_template_name,
            DATE_FORMAT(import_time, '%Y-%m-%d %H:%i:%s'),session_ach_slice,target_count 
            from yicall_{company_id}.b_{business_id}_callout_task where task_status in (1, 20) and 
            import_time BETWEEN '{start_time}' and '{end_time}';"""
            self.cursor.execute(sql)
            result = self.cursor.fetchall()
            if len(result) == 0:
                logging.info(f"yicall_{company_id}下{business_id}不存在待开启任务！")
            else:
                logging.info(
                    f"yicall_{company_id}下{business_id}存在待开启任务：\n{data2beautify(result)}"
                )
            return result
        else:
            logging.warning(f"yicall_{company_id}不需要进行通知！")
            return None


def notice(env: str = "dev"):
    start_task_notice = StartTaskNotice(env)
    need_handle_business = start_task_notice.query_business()
    if len(need_handle_business) < 1:
        logging.warning(f"没有查询到需要处理的账号业务！")
    else:
        for business_info in need_handle_business:
            company_id, business_id, business_name = business_info
            need_start_tasks = start_task_notice.query_task_info(
                company_id, business_id
            )
            if need_start_tasks is not None:
                for task_info in need_start_tasks:
                    task_id = task_info[0]
                    task_name = task_info[1]
                    task_status = task_info[2]
                    task_status_desc = task_status_info.get(task_status)
                    scene_name = task_info[3]
                    import_time = task_info[4]
                    session_ach_slice = task_info[5]
                    target_count = task_info[6]
                    if session_ach_slice:  # 任务是拨打过的
                        session_ach_slice_split = session_ach_slice.split(",")
                        task_called_count = 0
                        for (
                            x
                        ) in (
                            session_ach_slice_split
                        ):  # 查询任务在每个月下的拨打数量，isLastCall可以手机号去重
                            es_index = (
                                f"yicall_{company_id}_{business_id}_callout_session{x}"
                            )
                            body = {
                                "query": {
                                    "bool": {
                                        "filter": [
                                            {"term": {"taskId": task_id}},
                                            {"term": {"isLastCall": True}},
                                        ]
                                    }
                                }
                            }
                            single_month_count = start_task_notice.query_es(
                                es_index, body
                            )
                            task_called_count += single_month_count
                        need_call_count = target_count - task_called_count
                        if need_call_count > 0:
                            msg = (
                                f"🔥<font color=red>**有任务导入号码，请尽快开启外呼！**</font>\n"
                                f"**业务**：{business_name}\n"
                                f"**场景**：{scene_name}\n"
                                f"**任务**：{task_name}\n"
                                f"**任务状态**：{task_status_desc}\n"
                                f"**待拨数量**：{need_call_count}\n"
                                f"**导入时间**：{import_time}\n"
                                f"[**🍺 即刻前往**](http://aiforce-aibpo.ibot.ai/#/user/login)"
                            )
                            # 如果是樊登的待开启任务，另外推送一次
                            if company_id == start_task_notice.fandeng_company_id:
                                wecom_push_msg(start_task_notice.fandeng_push_url, msg)
                            wecom_push_msg(start_task_notice.push_url, msg)
                    else:  # 任务从未拨打
                        msg = (
                            f"🔥<font color=red>**有任务导入号码，请尽快开启外呼！**</font>\n"
                            f"**业务**：{business_name}\n"
                            f"**场景**：{scene_name}\n"
                            f"**任务**：{task_name}\n"
                            f"**任务状态**：{task_status_desc}\n"
                            f"**待拨数量**：{target_count}\n"
                            f"**导入时间**：{import_time}\n"
                            f"[**🍺 即刻前往**](http://aiforce-aibpo.ibot.ai/#/user/login)"
                        )
                        # 如果是樊登的待开启任务，另外推送一次
                        if company_id == start_task_notice.fandeng_company_id:
                            wecom_push_msg(start_task_notice.fandeng_push_url, msg)
                        wecom_push_msg(start_task_notice.push_url, msg)


if __name__ == "__main__":
    # notice('dev')
    scheduler = BlockingScheduler()
    scheduler.add_job(
        notice, args=["pls"], trigger="cron", hour="9-12,14-20", minute="0,15"
    )
    scheduler.start()
